Export resolveI18nLabel and fix i18n label type errors in plugin-designer#901
Export resolveI18nLabel and fix i18n label type errors in plugin-designer#901
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…n label handling in plugin-designer Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes TypeScript build failures caused by treating NavigationItem.label (string | i18n object) as a plain string across plugin-designer and components, by standardizing label rendering through resolveI18nLabel exported from @object-ui/react.
Changes:
- Re-export
resolveI18nLabelfrom@object-ui/reactto unblock downstream imports. - Update
NavigationDesignerto resolve labels to strings at all UI/editing usage sites. - Update
AppCreationWizardnavigation preview to render labels viaresolveI18nLabel.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/react/src/index.ts | Re-exports resolveI18nLabel to make label resolution available to other packages. |
| packages/plugin-designer/src/NavigationDesigner.tsx | Uses resolveI18nLabel for label draft state + rendering to avoid union-type misuse. |
| packages/plugin-designer/src/AppCreationWizard.tsx | Resolves navigation preview labels via resolveI18nLabel to fix ReactNode typing errors. |
| export { resolveI18nLabel } from './utils/i18n'; | ||
|
|
There was a problem hiding this comment.
resolveI18nLabel is now part of the public @object-ui/react API, but its current fallback uses label.defaultValue || label.key, which will ignore an intentionally empty-string defaultValue and show the key instead. Consider switching the implementation to nullish coalescing (defaultValue ?? key) so empty strings are preserved while still falling back when defaultValue is truly missing.
| export { resolveI18nLabel } from './utils/i18n'; | |
| import { resolveI18nLabel as baseResolveI18nLabel } from './utils/i18n'; | |
| export function resolveI18nLabel( | |
| ...args: Parameters<typeof baseResolveI18nLabel> | |
| ): ReturnType<typeof baseResolveI18nLabel> { | |
| const [label] = args; | |
| if ( | |
| label && | |
| typeof label === 'object' && | |
| 'defaultValue' in label && | |
| (label as { defaultValue?: unknown }).defaultValue === '' | |
| ) { | |
| // Preserve intentionally empty-string default values instead of falling back to the key | |
| return '' as ReturnType<typeof baseResolveI18nLabel>; | |
| } | |
| return baseResolveI18nLabel(...args); | |
| } |
| const [editingLabel, setEditingLabel] = useState(false); | ||
| const [labelDraft, setLabelDraft] = useState(item.label); | ||
| const [labelDraft, setLabelDraft] = useState(resolveI18nLabel(item.label) ?? ''); | ||
| const [editingIcon, setEditingIcon] = useState(false); |
There was a problem hiding this comment.
Test coverage: the new label resolution path should be exercised with a NavigationItem.label i18n object (e.g. { key, defaultValue }) to ensure the designer renders/edits without runtime errors and shows the expected fallback string. Adding a focused test case in NavigationDesigner.test.tsx would prevent regressions for this union type.
| <span className="flex-1 truncate text-sm text-gray-800"> | ||
| {item.type === 'separator' ? t('appDesigner.separatorLabel') : item.label} | ||
| {item.type === 'separator' ? t('appDesigner.separatorLabel') : resolveI18nLabel(item.label)} | ||
| </span> |
There was a problem hiding this comment.
Test coverage: since the navigation preview now resolves item.label via resolveI18nLabel, add a test case in AppCreationWizard.test.tsx with an i18n-object label to ensure the preview renders the expected fallback string (and doesn’t regress back to TS/ReactNode issues).
NavigationItem.labelis typed asstring | { key; defaultValue?; params? }but several files treat it as a plainstring, causing TS2322/TS2339 build failures acrossplugin-designerandcomponents.packages/react/src/index.ts— ExportresolveI18nLabelfrom./utils/i18n. It was defined but not re-exported, breaking imports inbreadcrumb.tsxandheader-bar.tsx.packages/plugin-designer/src/NavigationDesigner.tsx— Resolve i18n labels to strings at all 5 usage sites (state init, commit handler, escape reset, display render, preview render).packages/plugin-designer/src/AppCreationWizard.tsx— Wrapitem.labelwithresolveI18nLabel()in nav preview list.Original prompt
09:55:37.275 @object-ui/plugin-designer:build: �[96msrc/AppCreationWizard.tsx�[0m:�[93m527�[0m:�[93m17�[0m - �[91merror�[0m�[90m TS2322: �[0mType 'string | { key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'ReactNode'.
09:55:37.275 @object-ui/plugin-designer:build: Type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'ReactNode'.
09:55:37.276 @object-ui/plugin-designer:build: Type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is missing the following properties from type 'ReactPortal': children, type, props
09:55:37.276 @object-ui/plugin-designer:build: �[96msrc/NavigationDesigner.tsx�[0m:�[93m151�[0m:�[93m20�[0m - �[91merror�[0m�[90m TS2339: �[0mProperty 'trim' does not exist on type 'string | { key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }'.
09:55:37.276 @object-ui/plugin-designer:build: Property 'trim' does not exist on type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }'.
09:55:37.276 @object-ui/plugin-designer:build: �[96msrc/NavigationDesigner.tsx�[0m:�[93m152�[0m:�[93m41�[0m - �[91merror�[0m�[90m TS2339: �[0mProperty 'trim' does not exist on type 'string | { key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }'.
09:55:37.276 @object-ui/plugin-designer:build: Property 'trim' does not exist on type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }'.
09:55:37.277 @object-ui/plugin-designer:build: �[96msrc/NavigationDesigner.tsx�[0m:�[93m240�[0m:�[93m13�[0m - �[91merror�[0m�[90m TS2322: �[0mType 'string | { key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'string | number | readonly string[] | undefined'.
09:55:37.277 @object-ui/plugin-designer:build: Type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'string | number | readonly string[] | undefined'.
09:55:37.277 @object-ui/plugin-designer:build: �[96msrc/NavigationDesigner.tsx�[0m:�[93m266�[0m:�[93m13�[0m - �[91merror�[0m�[90m TS2322: �[0mType 'string | { key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'ReactNode'.
09:55:37.278 @object-ui/plugin-designer:build: Type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'ReactNode'.
09:55:37.278 @object-ui/plugin-designer:build: Type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is missing the following properties from type 'ReactPortal': children, type, props
09:55:37.278 @object-ui/plugin-designer:build: �[96msrc/NavigationDesigner.tsx�[0m:�[93m413�[0m:�[93m36�[0m - �[91merror�[0m�[90m TS2322: �[0mType 'string | { key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'ReactNode'.
09:55:37.278 @object-ui/plugin-designer:build: Type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is not assignable to type 'ReactNode'.
09:55:37.278 @object-ui/plugin-designer:build: Type '{ key: string; defaultValue?: string | undefined; params?: Record<string, any> | undefined; }' is missing the following properties from type 'ReactPortal': children, type, props
09:55:59.698 @object-ui/components:build: �[96msrc/renderers/data-display/breadcrumb.tsx�[0m:�[93m13�[0m:�[93m10�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/react"' has no exported member 'resolveI18nLabel'.
09:55:59.698 @object-ui/components:build: �[96msrc/renderers/navigation/header-bar.tsx�[0m:�[93m12�[0m:�[93m10�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/react"' has no exported member 'resolveI18nLabel'.
09:56:42.560 @object-ui/plugin-list:build: �[31merror during build:
09:56:42.567 @object-ui/plugin-list:build: at error (file:///vercel/path0/node_modules/.pnpm/rollup@4.57.1/node_modules/rollup/dist/es/shared/parseAst.js:398:42)
09:56:42.667 @object-ui/plugin-list:build: ELIFECYCLE Command failed with exit code 1.
09:56:42.680 @object-ui/plugin-list:build: ERROR: command finished with error: command (/vercel/path0/packages/plugin-list) /vercel/.local/share/pnpm/.tools/pnpm/10.28.2/bin/pnpm run build exited (1)
09:56:42.740 @object-ui/fields:build: ELIFECYCLE Command failed.
09:56:42.746 @object-ui/plugin-list#build: command (/vercel/path0/packages/plugin-list) /vercel/.local/share/pnpm/.tools/pnpm/10.28.2/bin/pnpm run build exited (1)
09:56:42.763 ERROR run failed: command exited (1)
09:56:42.782 Error: Command "cd ../.. && pnpm turbo run build --filter=@object-ui/console^... && cd apps...
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.